package com.dy.yunying.biz.service.currency.impl;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.regex.Pattern;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.dy.yunying.api.db.user.UserInfo;
import com.dy.yunying.api.dto.currency.UserCurrencyRecordDto;
import com.dy.yunying.api.entity.GameRole;
import com.dy.yunying.api.entity.ParentGameDO;
import com.dy.yunying.api.entity.WanGameDO;
import com.dy.yunying.api.entity.currency.UserCurrencyRecord;
import com.dy.yunying.api.enums.CurrencyChangeTypeEnum;
import com.dy.yunying.api.enums.CurrencySourceTypeEnum;
import com.dy.yunying.api.enums.CurrencyTypeEnum;
import com.dy.yunying.api.req.currency.UserCurrencyRecordReq;
import com.dy.yunying.api.vo.UserCurrencyRecordVO;
import com.dy.yunying.biz.config.YunYingProperties;
import com.dy.yunying.biz.dao.manage.GameRoleMapper;
import com.dy.yunying.biz.dao.manage.ParentGameDOMapper;
import com.dy.yunying.biz.dao.manage.WanGameDOMapper;
import com.dy.yunying.biz.dao.manage.currency.UserCurrencyRecordMapper;
import com.dy.yunying.biz.mongo.UserCurrencyRecordMongo;
import com.dy.yunying.biz.service.currency.UserCurrencyRecordService;
import com.dy.yunying.biz.utils.mongo.MongoDBUtil;
import com.pig4cloud.pig.common.core.util.R;
import lombok.RequiredArgsConstructor;
import lombok.extern.log4j.Log4j2;

/**
* @author hejiale
* @description 针对表【user_currency_record(账号平台币信息)】的数据库操作Service实现
* @createDate 2022-03-25 09:56:27
*/
@Log4j2
@Service("userCurrencyRecordService")
@RequiredArgsConstructor
public class UserCurrencyRecordServiceImpl extends ServiceImpl<UserCurrencyRecordMapper, UserCurrencyRecord>
    implements UserCurrencyRecordService {

	private final UserCurrencyRecordMapper userCurrencyRecordMapper;
	private final GameRoleMapper gameRoleMapper;
	private final MongoTemplate mongoTemplate;
	private final ParentGameDOMapper parentGameDOMapper;
	private final WanGameDOMapper wanGameDOMapper;
	private final YunYingProperties yunYingProperties;
	private final UserCurrencyRecordMongo userCurrencyRecordMongo;

	/**
	 * 领取记录列表 - page
	 * @param req
	 * @return
	 */
	@Override
	public R<IPage<UserCurrencyRecordVO>> pageDto(UserCurrencyRecordReq req){
		return R.ok(getDate(req));
	}
	/**
	 * 导出
	 * @param req
	 * @return
	 */
	@Override
	public List<UserCurrencyRecordDto> exportRecord(UserCurrencyRecordReq req){
		req.setCurrent(1);
		req.setSize(999999);
		IPage<UserCurrencyRecordDto> iPage = userCurrencyRecordMapper.pageDto(req);
		// 处理数据
		List<UserCurrencyRecordDto> list = iPage.getRecords();
		return list;
	}
	
	@SuppressWarnings({ "unchecked", "rawtypes" })
	private Page<UserCurrencyRecordVO> getDate(UserCurrencyRecordReq req){
		Query query = this.setQueryCondion(req);
		long total = mongoTemplate.count(query, UserCurrencyRecordVO.class, userCurrencyRecordMongo.getCollctionName());
		PageRequest pageable = this.setPageOrder(req, query);
		List<UserCurrencyRecordVO> result = mongoTemplate.find(query, UserCurrencyRecordVO.class, userCurrencyRecordMongo.getCollctionName());
		if(CollectionUtils.isNotEmpty(result)){
			//填充四个属性值 r.role_name   g.gname(game_name)   pg.gname(parent_game_name)  username
			this.setResultValue(result);
		}
		org.springframework.data.domain.Page<UserCurrencyRecordDto> res = new PageImpl(result, pageable, total);
		Page<UserCurrencyRecordVO> resultPage = new Page<>(req.getCurrent(), req.getSize());
		resultPage.setTotal(res.getTotalElements());
		resultPage.setRecords(result);
		return resultPage;
	}
	
	/**
	 * 设置分页排序
	 */
	private PageRequest setPageOrder(UserCurrencyRecordReq req,Query query){
		PageRequest pageable = PageRequest.of((int)req.getCurrent() -1, (int)req.getSize());
		List<OrderItem> orders = req.getOrders();
		for (OrderItem orderItem : orders) {
			String column = orderItem.getColumn();
			boolean asc = orderItem.isAsc();
			if(asc){
				query.with(Sort.by(Sort.Direction.ASC, column));
			}else{
				query.with(Sort.by(Sort.Direction.DESC, column));
			}
		}
		query.with(pageable);
		return pageable;
	}
	
	/**
	 * 拼接查询条件
	 * @param req
	 * @return
	 */
	private Query setQueryCondion(UserCurrencyRecordReq req){
		Query query = new Query();
		//拼接等值查询条件
		Map<String,Object> andQueryMap = new HashMap<>();
		Long userid = req.getUserid();
		
		String sourceId1 = req.getSourceId1(); // == 
		String ip = req.getIp(); // == 
		andQueryMap.put("user_id",userid);
		
		if(Objects.nonNull(CurrencySourceTypeEnum.getOneByVal(req.getSourceType()))){
			String sourceType = CurrencySourceTypeEnum.getOneByVal(req.getSourceType()).getDesc();
			andQueryMap.put("source_type",sourceType);
		}
		
		if(Objects.nonNull(CurrencyChangeTypeEnum.getOneByVal(req.getType()))){
			String recordType = CurrencyChangeTypeEnum.getOneByVal(req.getType()).getDesc();
			andQueryMap.put("record_type",recordType);
		}
		
		if(Objects.nonNull(CurrencyChangeTypeEnum.getOneByVal(req.getCurrencyType()))){
			String currencyType = CurrencyChangeTypeEnum.getOneByVal(req.getCurrencyType()).getDesc();
			andQueryMap.put("currency_type",currencyType);
		}
		
		andQueryMap.put("source_id1",sourceId1);
		andQueryMap.put("client_ip",ip);
		andQueryMap.put("is_deleted",0);
		Criteria criteria = MongoDBUtil.getCriteria(new Criteria(), andQueryMap);
		
		//开始时间
		Date startTime = req.getStartTime();
		Date endTime = req.getEndTime();
		if(Objects.nonNull(startTime)){
			criteria.andOperator(
					Criteria.where("create_time").gte(MongoDBUtil.dateToISODate(startTime)),
					Criteria.where("create_time").lte(MongoDBUtil.dateToISODate(endTime))
					);
		}
		String username = req.getUsername(); // %like%
		Set<Long> userIds = new HashSet<>();
		if(StringUtils.isNoneBlank(username)){
			//查询用户表
			Pattern pattern = Pattern.compile("^.*" + username + ".*$", Pattern.CASE_INSENSITIVE);
			Query queryUser = new Query(Criteria.where("username").regex(pattern));
			List<UserInfo> find = mongoTemplate.find(queryUser, UserInfo.class, MongoDBUtil.getCollectionName(UserInfo.class, yunYingProperties.getPlatFormCode()));
			for (UserInfo userInfo : find) {
				 Long id = userInfo.getId();
				 userIds.add(id);
			}
			criteria.and("user_id").in(userIds);
		}
		//pgids  gameIds
		String gameIds = req.getGameIds();
		String pgids = req.getPgids();
		if(StringUtils.isNoneBlank(gameIds) && StringUtils.isNoneBlank(pgids)){
			Set<Integer> pgidsList = new HashSet<>();
			Set<Integer> gameIdsList = new HashSet<>();
			Arrays.asList(pgids.split(",")).forEach(e -> pgidsList.add(Integer.parseInt(e)));;
			Arrays.asList(gameIds.split(",")).forEach(e -> gameIdsList.add(Integer.parseInt(e)));;
			
			criteria.orOperator(
					Criteria.where("game_sub").in(gameIdsList),
					Criteria.where("game_main").in(pgidsList)
					);
		}
		
		//sourceId 
		String sourceId = req.getSourceId();
		if(StringUtils.isNoneBlank(sourceId)){
			criteria.and("source_id1").is(sourceId).orOperator(Criteria.where("source_id2").is(sourceId));
		}
		
		//sourceName
		String sourceName = req.getSourceName();
		if(StringUtils.isNoneBlank(sourceName)){
			Pattern compile = Pattern.compile("^.*" + sourceName + ".*$", Pattern.CASE_INSENSITIVE);
			criteria.and("source_name1").regex(compile).orOperator(Criteria.where("source_name2").regex(compile));
		}
		
		String areaIds = req.getAreaIds();
		if(StringUtils.isNoneBlank(areaIds)){
			List<String> areaIdsList = Arrays.asList(areaIds.split(","));
			criteria.and("area_id").in(areaIdsList);
		}
		//改造连表
		String roleName = req.getRoleName();
		if(StringUtils.isNoneBlank(roleName)){
			Set<String> roleIds = gameRoleMapper.getGameRoleIds(roleName);
			if(CollectionUtils.isNotEmpty(roleIds)){
				 criteria.and("role_id").in(roleIds);
			}
		}
		//设置分页 设置排序
		//查询总数
		query.addCriteria(criteria);
		return query;
	}
	
	/**
	 * 设置关联表属性值
	 * @param result
	 */
	private void setResultValue(List<UserCurrencyRecordVO> result){
		Map<Long,List<Integer>> rgameMap= new HashMap<>();
		Map<Long,List<Integer>> pgameMap= new HashMap<>();
		Map<Long,List<Integer>> wgameMap= new HashMap<>();
		Map<Long,List<Integer>> userMap= new HashMap<>();
		for (int i = 0; i < result.size(); i++) {
			UserCurrencyRecordVO vo = result.get(i);
			vo.setSourceType(CurrencySourceTypeEnum.getNameByDesc(vo.getSourceType()));
			vo.setCurrencyType(CurrencyTypeEnum.getNameByDesc(vo.getCurrencyType()));
			vo.setRecordType(CurrencyChangeTypeEnum.getNameByDesc(vo.getRecordType()));
			Long pgid = vo.getGameMain();
			Long gameId = vo.getGameSub();
			Long userId2 = vo.getUserId();
			putMap(rgameMap, pgid, i);
			putMap(pgameMap, pgid, i);
			putMap(wgameMap, gameId, i);
			putMap(userMap, userId2, i);
		}
		List<GameRole> gameRoleList = gameRoleMapper.getGameRoleByPgids(rgameMap.keySet());
		List<ParentGameDO> parentGameDOList  = parentGameDOMapper.getParentGameByPgids(rgameMap.keySet());
		List<WanGameDO> wanGameList= wanGameDOMapper.getWanGameByGameIds(wgameMap.keySet());
		
		Query queryUser = new Query(Criteria.where("_id").in(userMap.keySet()));
		List<UserInfo> userList = mongoTemplate.find(queryUser, UserInfo.class, MongoDBUtil.getCollectionName(UserInfo.class, yunYingProperties.getPlatFormCode()));
		
		this.setGameRoleName(rgameMap, result, gameRoleList);
		this.setParentGameName(pgameMap, result, parentGameDOList);
		this.setGameName(wgameMap, result, wanGameList);
		this.setUserName(userMap,result,userList);
	}
	
	private void putMap(Map<Long,List<Integer>> map, Long key, Integer value){
		if(map.containsKey(key)){
			map.get(key).add(value);
		}else{
			List<Integer> list = new ArrayList<>();
			list.add(value);
			map.put(key, list);
		}
	}
	
	/**
	 * 设置roleName
	 * @param rgameMap
	 * @param result
	 * @param gameRoleList
	 */
	private void setGameRoleName(Map<Long,List<Integer>> rgameMap,List<UserCurrencyRecordVO> result,List<GameRole> gameRoleList){
		for (GameRole gameRole : gameRoleList) {
			Long pgameId = gameRole.getPgameId();
			List<Integer> list = rgameMap.get(pgameId);
			if(CollectionUtils.isEmpty(list)){
				continue;
			}
			String roleName = gameRole.getRoleName();
			for (Integer index : list) {
				result.get(index).setRoleName(roleName);
			}
		}
	}
	
	/**
	 * 设置ParentGameName
	 * @param pgameMap
	 * @param result
	 * @param parentGameDOList
	 */
	private void setParentGameName(Map<Long,List<Integer>> pgameMap,List<UserCurrencyRecordVO> result,List<ParentGameDO> parentGameDOList){
		for (ParentGameDO parentGameDO : parentGameDOList) {
			Long id = parentGameDO.getId();
			List<Integer> list = pgameMap.get(id);
			if(CollectionUtils.isEmpty(list)){
				continue;
			}
			String gname = parentGameDO.getGname();
			for (Integer index : list) {
				result.get(index).setParentGameName(gname);
			}
		}
	}
	
	/**
	 * 设置GameName
	 * @param pgameMap
	 * @param result
	 * @param parentGameDOList
	 */
	private void setGameName(Map<Long,List<Integer>> wgameMap,List<UserCurrencyRecordVO> result,List<WanGameDO> wanGameList){
		for (WanGameDO wanGameDO : wanGameList) {
			Long id = wanGameDO.getId();
			List<Integer> list = wgameMap.get(id);
			if(CollectionUtils.isEmpty(list)){
				continue;
			}
			String gname = wanGameDO.getGname();
			for (Integer index : list) {
				result.get(index).setGameName(gname);
			}
		}
	}
	
	/**
	 * 设置username
	 * @param pgameMap
	 * @param result
	 * @param parentGameDOList
	 */
	private void setUserName(Map<Long, List<Integer>> userMap,List<UserCurrencyRecordVO> result,List<UserInfo> userList){
		for (UserInfo userInfo : userList) {
			Long id = userInfo.getId();
			List<Integer> list = userMap.get(id);
			if(CollectionUtils.isEmpty(list)){
				continue;
			}
			String username = userInfo.getUsername();
			for (Integer index : list) {
				result.get(index).setUsername(username);
			}
		}
	}

}


